package von.seiji.cn;

import cn.hutool.core.util.EscapeUtil;
import cn.hutool.core.util.StrUtil;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.springframework.web.multipart.MultipartFile;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
import org.wltea.analyzer.lucene.IKAnalyzer;
import von.seiji.cn.asset.Algorithm;
import von.seiji.cn.asset.Base64DecodeMultipartFile;
import von.seiji.cn.asset.Charsets;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.List;

/**
 * @author: Amasawa Seiji
 * @DateTime: 2020/12/19 17:55
 * @Description: 暂无描述
 */
public abstract class SelfUtil {

    private static final char[][] TEXT = new char[64][];
    public static final String NBSP = StrUtil.HTML_NBSP;
    public static final String AMP = StrUtil.HTML_AMP;
    public static final String QUOTE = StrUtil.HTML_QUOTE;
    public static final String APOS = StrUtil.HTML_APOS;
    public static final String LT = StrUtil.HTML_LT;
    public static final String GT = StrUtil.HTML_GT;

    public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
    public static final String RE_SCRIPT = "<[\\s]*?script[^>]*?>.*?<[\\s]*?\\/[\\s]*?script[\\s]*?>";

    static {
        for (int i = 0; i < 64; i++) {
            TEXT[i] = new char[]{(char) i};
        }

        // special HTML characters
        TEXT['\''] = "&#039;".toCharArray(); // 单引号 ('&apos;' doesn't work - it is not by the w3 specs)
        TEXT['"'] = QUOTE.toCharArray(); // 单引号
        TEXT['&'] = AMP.toCharArray(); // &符
        TEXT['<'] = LT.toCharArray(); // 小于号
        TEXT['>'] = GT.toCharArray(); // 大于号
    }

    public static String drawAscii(String greychar, File srcImg) {
        try {
            return drawAscii(greychar, (InputStream) (new FileInputStream(srcImg)));
        } catch (FileNotFoundException var3) {
            return null;
        }
    }

    public static String drawAscii(String greyChar, InputStream inputStream) {
        StringBuilder builder = new StringBuilder();
        int length = greyChar.length();
        try {
            BufferedImage image = ImageIO.read(inputStream);
            int height = image.getHeight();
            int width = image.getWidth();

            for (int j = 0; j < height; j += 2) {
                for (int i = 0; i < width; ++i) {
                    int rgb = image.getRGB(i, j);
                    int r = rgb & 0xff;
                    int g = rgb >> 8 & 0xff;
                    int b = rgb >> 16 & 0xff;
                    double v = (r * 299 + g * 587 + b * 114) / 1000D;
                    builder.append(greyChar.charAt((int) (v / 256 * length)));
                }
                builder.append(Charsets.LINE_SEPARATOR_WINDOWS);
            }
            return builder.toString();
        } catch (IOException var12) {
            return null;
        }
    }

    public static float scoreSimilarity(String str1, String str2) {
        int len1 = str1.length();
        int len2 = str2.length();
        int[][] dif = new int[len1 + 1][len2 + 1];

        int a;
        for (a = 0; a <= len1; dif[a][0] = a++) {
        }

        for (a = 0; a <= len2; dif[0][a] = a++) {
        }

        for (int i = 1; i <= len1; ++i) {
            for (int j = 1; j <= len2; ++j) {
                byte temp;
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    temp = 0;
                } else {
                    temp = 1;
                }

                dif[i][j] = min(dif[i - 1][j - 1] + temp, dif[i][j - 1] + 1, dif[i - 1][j] + 1);
            }
        }

        return 1.0F - (float) dif[len1][len2] / (float) Math.max(str1.length(), str2.length());
    }

    private static int min(int... is) {
        int min = 2147483647;
        int[] var2 = is;
        int var3 = is.length;

        for (int var4 = 0; var4 < var3; ++var4) {
            int i = var2[var4];
            if (min > i) {
                min = i;
            }
        }

        return min;
    }

    public static List<String> ikAnalyzer(String text, boolean useSmart) {
        ArrayList<String> list = new ArrayList();
        IKSegmenter ikSegmenter = new IKSegmenter(new StringReader(text), useSmart);

        Lexeme next = null;
        while (true) {
            try {
                if (null == (next = ikSegmenter.next())) {
                    break;
                }
            } catch (IOException e) {
            }
            list.add(next.getLexemeText());
        }

        return list;
    }

    public static List<String> analyzer(String text, boolean useSmart) {
        ArrayList<String> list = new ArrayList();
        TokenStream tokenStream = null;
        try {
            tokenStream = (new IKAnalyzer(useSmart)).tokenStream(null, text);
            tokenStream.addAttribute(CharTermAttribute.class);
            tokenStream.reset();

            while (tokenStream.incrementToken()) {
                CharTermAttribute attribute = tokenStream.getAttribute(CharTermAttribute.class);
                list.add(attribute.toString());
            }
        } catch (IOException e) {
        }
        return list;
    }

 /*   public static double scoreDeterminants(double[][] arrays) {
        int length = arrays.length;
        if (length == 1) {
            return arrays[0][0];
        } else {
            double total = 0.0D;

            for (int i = 0; i < length; ++i) {
                double[][] _arrays = new double[length - 1][length - 1];

                for (int j = 0; j < _arrays.length; ++j) {
                    for (int k = 0; k < _arrays.length; ++k) {
                        _arrays[(j + i) % _arrays.length][k] = arrays[(i + 1 + j) % arrays.length][k + 1];
                    }
                }

                total += arrays[i][0] * Math.pow(-1.0D, (double) i) * scoreDeterminants(_arrays);
            }

            return total;
        }
    }*/

    /**
     * 行列式计算（二维数组）
     *
     * @param arrays
     * @return
     */
    public static double scoreDeterminants(double[][] arrays) {
        int length = arrays.length;
        if (length == 2) {
            return arrays[0][0] * arrays[1][1] - arrays[0][1] * arrays[1][0];
        } else {
            double total = 0D;
            for (int i = 0; i < length; ++i) {
                double[][] _arrays = new double[length - 1][length - 1];
                int index = 0;
                for (int i1 = 0; i1 < arrays.length; i1++) {
                    if (i == i1) {
                        continue;
                    }
                    System.arraycopy(arrays[i1], 1, _arrays[index++], 0, length - 1);
                }
                total += arrays[i][0] * Math.pow(-1, i) * scoreDeterminants(_arrays);
            }
            return total;
        }
    }

    private static final char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static String str2Hash(String str, Algorithm algorithm) {
        MessageDigest md = null;

        try {
            md = MessageDigest.getInstance(algorithm.value());
        } catch (NoSuchAlgorithmException var4) {
        }
        md.update(str.getBytes());
        byte[] digest = md.digest();
        int length = digest.length;
        char[] chars = new char[length * 2];
        for (int i = 0, k = 0; i < length; ++i) {
            chars[k++] = hexDigits[digest[i] >>> 4 & 15];
            chars[k++] = hexDigits[digest[i] & 15];
        }
        return new String(chars);
    }

    private static final char[] miarry = new char[]{'@', 'G', 'a', 'w', '^', '2', 't', 'G', 'Q', '6', '1', '-', 'Î', 'Ò', 'n', 'i'};

    public static String toKrcText(File krcFile) {
        try {
            FileInputStream stream = new FileInputStream(krcFile);
            return toKrcText(stream);
        } catch (FileNotFoundException var3) {
            return null;
        }
    }

    public static String toKrcText(FileInputStream fis) {
        byte[] top = new byte[4];

        try {
            byte[] zip_byte = new byte[fis.available()];
            fis.read(top);
            fis.read(zip_byte);
            int j = zip_byte.length;

            for (int k = 0; k < j; ++k) {
                int l = k % 16;
                zip_byte[k] = (byte) (zip_byte[k] ^ miarry[l]);
            }

            String var18 = new String(ZLibUtil.decompress(zip_byte), "utf-8");
            return var18;
        } catch (IOException var16) {
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException var15) {
                }
            }

        }

        return null;
    }

    public static MultipartFile base64Convert2MultipartFile(String base64) {
        String[] baseStrs = base64.split(","); //base64编码后的图片有头信息所以要分离出来   [0]data:image/png;base64, 图片内容为索引[1]
        byte[] decode = Base64.getDecoder().decode(baseStrs[1]); //取索引为1的元素进行处理
        for (int i = 0; i < decode.length; ++i) {
            if (decode[i] < 0) {
                decode[i] += 256;
            }
        }
        //处理过后的数据通过Base64DecodeMultipartFile转换为MultipartFile对象
        return new Base64DecodeMultipartFile(decode, baseStrs[0]);

    }

    /*
     *去除集合中的空字符串以及过滤重复的字符串
     * */
    public static Set<String> picklist(List<String> list) {
        HashSet<String> set = new HashSet<>(list);
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()) {
            if (StrUtil.isBlank(iterator.next())) {
                iterator.remove();
            }
        }
        return set;
    }

    /**
     * 转义文本中的HTML字符为安全的字符，以下字符被转义：
     * <ul>
     * <li>' 替换为 &amp;#039; (&amp;apos; doesn't work in HTML4)</li>
     * <li>" 替换为 &amp;quot;</li>
     * <li>&amp; 替换为 &amp;amp;</li>
     * <li>&lt; 替换为 &amp;lt;</li>
     * <li>&gt; 替换为 &amp;gt;</li>
     * </ul>
     *
     * @param text 被转义的文本
     * @return 转义后的文本
     */
    public static String escape(String text) {
        return encode(text);
    }

    /**
     * Encoder
     *
     * @param text 被编码的文本
     * @return 编码后的字符
     */
    private static String encode(String text) {
        int len;
        if ((text == null) || ((len = text.length()) == 0)) {
            return StrUtil.EMPTY;
        }
        StringBuilder buffer = new StringBuilder(len + (len >> 2));
        char c;
        for (int i = 0; i < len; i++) {
            c = text.charAt(i);
            if (c < 64) {
                buffer.append(TEXT[c]);
            } else {
                buffer.append(c);
            }
        }
        return buffer.toString();
    }

    /**
     * 还原被转义的HTML特殊字符
     *
     * @param htmlStr 包含转义符的HTML内容
     * @return 转换后的字符串
     */
    public static String unescape(String htmlStr) {
        if (StrUtil.isBlank(htmlStr)) {
            return htmlStr;
        }

        return EscapeUtil.unescapeHtml4(htmlStr);
    }

    public static int bitAdd(int a, int b) {
        if (b == 0) {
            return a;
        }
        int sum = a ^ b;
        int carry = (a & b) << 1;
        return bitAdd(sum, carry);
    }

    /**
     * 位运算比较a， b大小
     * @param a
     * @param b
     * @return
     */
    public static int compare(int a, int b) {
        int diff = a ^ b;

        if (0 == diff) return 0;

        // 001xxxxx -> 00100000
        diff |= diff >> 1;
        diff |= diff >> 2;
        diff |= diff >> 4;
        diff |= diff >> 8;
        diff |= diff >> 16;
        diff ^= diff >> 1;

        return 0 == (a & diff) ? 1 : -1;
    }

    /**
     * 求a，b之间的最大公约数
     * @param a
     * @param b
     * @return
     */
    public static int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }

    /**
     * 求a，b之间的最小公倍数
     * @param a
     * @param b
     * @return
     */
    public static int lcm(int a, int b) {
        return a * b / gcd(a, b);
    }


}
